package com.flash.dailyreport.util;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpConnectionManager;
import org.apache.commons.httpclient.HttpMethodBase;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.Map;


/**
 * Created by hanhaiwen on 22/02/2016.
 * <p/>
 * copy from lego core
 */
public class HttpClientUtils {
    private static final Logger logger = LoggerFactory.getLogger(HttpClientUtils.class);
    private volatile static HttpClientUtils httpClientUtils;
    private String DEFAULT_CHARSET = "UTF-8";
    private HttpClient httpClient;


    public HttpClientUtils() {
        httpClient = new HttpClient();
        HttpConnectionManager httpConnectionManager = new MultiThreadedHttpConnectionManager();
        HttpConnectionManagerParams params = new HttpConnectionManagerParams();
        params.setConnectionTimeout(30 * 1000);//连接超时时间
        params.setSoTimeout(30 * 1000);//socket获取数据时间
        params.setDefaultMaxConnectionsPerHost(50);
        params.setMaxTotalConnections(50);
        httpConnectionManager.setParams(params);
        httpClient.setHttpConnectionManager(httpConnectionManager);
        httpClient.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, DEFAULT_CHARSET);
    }

    public static HttpClientUtils getInstance() {
        if (httpClientUtils == null) {
            synchronized (HttpClientUtils.class) {
                if (httpClientUtils == null) {
                    httpClientUtils = new HttpClientUtils();
                }
            }
        }
        return httpClientUtils;
    }

    public HttpTextResponse doHttpGet(String url, Map<String, String> headerMap) {
        return exeHttpGetMethod(url, DEFAULT_CHARSET, null, headerMap);
    }

    public Result doGetEx(String url, Map<String, String> headerMap) {
        String strResponse = doGet(url, headerMap);
        if (!StringUtils.isEmpty(strResponse)) {
            return JSONObject.parseObject(strResponse, new TypeReference<Result>(){});
        }
        return null;
    }

    public String doGet(String url, Map<String, String> headerMap) {
        return exeGetMethod(url, DEFAULT_CHARSET, null, headerMap);
    }


    public Result exePostFormMethodEx(String url, Map<String, String> params) {
        HttpTextResponse textResponse = exePostFormMethod(url, params, null,null);
        return getResponse(textResponse);
    }

    /**
     * 执行post请求，数据格式为form
     *
     * @param url
     * @param params
     * @return
     */
    public HttpTextResponse exePostFormMethod(String url, Map<String, String> params) {
        return exePostFormMethod(httpClient, url, params, null,null);
    }


    /**
     * 执行post请求，支持cookie
     *
     * @param url
     * @param params
     * @param cookies
     * @return
     */
    public HttpTextResponse exePostFormMethod(String url, Map<String, String> params, Cookie[] cookies,Header header) {
        return exePostFormMethod(httpClient, url, params, cookies,header);
    }

    /**
     * 执行post请求，数据格式为form
     *
     * @param client
     * @param url
     * @param params
     * @return
     */
    private HttpTextResponse exePostFormMethod(HttpClient client, String url, Map<String, String> params, Cookie[] cookies,Header header) {

        PostMethod post = new PostMethod(url);
        if (cookies != null) {
            client.getState().addCookies(cookies);
        }
        post.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
        if(null!=header){
            post.setRequestHeader(header);
        }
        for (String key : params.keySet()) {
            String value = params.get(key);
            post.addParameter(key, value);
        }

        HttpTextResponse response = null;
        try {
            int code = client.executeMethod(post);
            logger.info("[post请求结果][url:{}][code:{}]", url, code);
            response = new HttpTextResponse(code, post, false);
        } catch (Exception e) {
            String msg = String.format("[系统错误][执行post请求发生错误:{%s},url:{%s},params:{%s}]",
                    e.getMessage(), url, JSONObject.toJSONString(params));
            logger.error(msg, e);
            response = HttpTextResponse.buildFailedResponse("500", msg);
        } finally {
            post.releaseConnection();
        }

        return response;
    }


    private String exeGetMethod(String url, String charset, Cookie[] cookies,
                                Map<String, String> headerMap) {
        HttpTextResponse response = exeHttpGetMethod(url, charset, cookies, headerMap);
        if (200 == response.getCode()) {
            return response.getResponseBody();
        } else {
            logger.info("[exeGetMethod][" + url + "][server response status code " +
                    "is " + response.getCode() + "]");
            return null;

        }
    }
    private HttpTextResponse exeHttpGetMethod(String url, String charset, Cookie[] cookies,
                                              Map<String, String> headerMap) {
        GetMethod method = new GetMethod(url);
        charset = charset == null ? DEFAULT_CHARSET : charset;
        logger.info("[exeHttpGetMethod] [url:{}] [charset:{}] [cookies:{}] [headerMap:{}]",
                url, charset == null ? DEFAULT_CHARSET : charset,
                (cookies == null ? "null" : JSONObject.toJSONString(cookies)),
                (headerMap == null ? "null" : JSONObject.toJSONString(headerMap)));
        setHeader(headerMap, method);
        if (cookies != null) {
            httpClient.getState().addCookies(cookies);
        }
        HttpTextResponse response = null;
        try {
            int code = httpClient.executeMethod(method);
            logger.info("[get请求结果][url:{}][code:{}]", url, code);
            response = new HttpTextResponse(code, method, false);
        } catch (Exception e) {
            String msg = String.format("[系统错误][执行get请求发生错误:{%s},url:{%s},params:{%s}]",
                    e.getMessage(), url, (headerMap == null ? "null" : JSONObject.toJSONString(headerMap)));
            logger.error(msg, e);
            response = HttpTextResponse.buildFailedResponse("500", msg);
        } finally {
            method.releaseConnection();
        }
        return response;

    }

    private static void setHeader(Map<String, String> headerMap, HttpMethodBase method) {
        if (headerMap != null) {
            Iterator entries = headerMap.entrySet().iterator();
            while (entries.hasNext()) {
                Map.Entry entry = (Map.Entry) entries.next();
                method.setRequestHeader(String.valueOf(entry.getKey()), String.valueOf(entry.getValue()));
            }
        }
    }


    public <T> Result postJsonEx(String url, T data, Cookie[] cookies) {
        HttpTextResponse textResponse = postJson(url, data, cookies);
        return getResponse(textResponse);
    }

    public <T> HttpTextResponse postJson(String url, T data, Cookie[] cookies) {
        logger.info("[post请求][url:{}][params:{}]", url, JSONObject.toJSONString(data));
        return postJson(url, JSONObject.toJSONString(data), cookies);
    }

    public Result postJsonEx(String url, String json) {
        HttpTextResponse textResponse = postJson(url, json);
        return getResponse(textResponse);
    }

    public HttpTextResponse postJson(String url, String json) {
        return postJson(url, json, null);
    }

    public HttpTextResponse postJson(String url, String json, Cookie[] cookies) {
        return postJson(url,json,cookies,null);
    }

    public HttpTextResponse postJson(String url, String json, Cookie[] cookies, Map headers) {
        logger.info("[post请求][url:{}][params:{}]", url, json);
        PostMethod post = new PostMethod(url);
        if (cookies != null) {
            httpClient.getState().addCookies(cookies);
        }
        setHeader(headers,post);
        try {
            RequestEntity requestEntity = new StringRequestEntity(json, "application/json;charset=UTF-8", "UTF-8");
            post.setRequestEntity(requestEntity);
        } catch (UnsupportedEncodingException e) {
            ;
        }

        HttpTextResponse response = null;
        try {
            int code = httpClient.executeMethod(post);
            logger.info("[post请求结果][url:{}][code:{}][response:{}]", url, code, post.getResponseBodyAsString());
            response = new HttpTextResponse(code, post, false);
        } catch (Exception e) {
            String msg = String.format("[系统错误][执行post请求发生错误:{%s},url:{%s},json:{%s}]",
                    e.getMessage(), url, json);
            logger.error(msg, e);
            response = HttpTextResponse.buildFailedResponse("500", msg);
        } finally {
            post.releaseConnection();
        }
        return response;
    }

    /**
     * 发送put请求
     *
     * @param url
     * @param data
     * @param cookies
     * @param <T>
     * @return
     */
    public <T> HttpTextResponse postJsonByPutMethod(String url, T data, Cookie[] cookies) {
        logger.info("[put请求][url:{}][params:{}]", url, JSONObject.toJSONString(data));
        PutMethod put = new PutMethod(url);
        if (cookies != null) {
            httpClient.getState().addCookies(cookies);
        }
        try {
            RequestEntity requestEntity = new StringRequestEntity(JSONObject.toJSONString(data), "application/json;charset=UTF-8", "UTF-8");
            put.setRequestEntity(requestEntity);
        } catch (UnsupportedEncodingException e) {
            ;
        }
        HttpTextResponse response = null;
        try {
            int code = httpClient.executeMethod(put);
            logger.info("[post请求结果][url:{}][code:{}]", url, code);
            response = new HttpTextResponse(code, put, false);
        } catch (Exception e) {
            String msg = String.format("[系统错误][执行put请求发生错误:{%s},url:{%s},json:{%s}]",
                    e.getMessage(), url, JSONObject.toJSONString(data));
            logger.error(msg, e);
            response = HttpTextResponse.buildFailedResponse("500", msg);
        } finally {
            put.releaseConnection();
        }
        return response;
    }

    private Result getResponse(HttpTextResponse textResponse) {
        if (200 != textResponse.getCode()) {
            throw new RuntimeException("network error return code:" + textResponse.getCode());
            //throw new NetworkException(String.valueOf(textResponse.getCode()), "network error return code:" + textResponse.getCode());
        } else {
            String responseBody = textResponse.getResponseBody();
            Result resMap = JSONObject.parseObject(responseBody, new TypeReference<Result>() {});
            return resMap;
        }
    }
}
